-- CreationGateM
-- Created by huanghr
-- 创世之门奖励模块

module("CreationGateM", package.seeall);

-- 创世之门建筑奖励
local CreationGateBonusTable = {};
-- 创世之门夹层表
local CreationUnrealTable = {};
-- 创世之门角色表
local RoleTypeInfo = {};
-- 角色发言模板
local CreationGateDialogTable = {};
-- 角色随机发言内容（creation_unreal.csv表中）
-- 如果新添发言考虑使用新表
local RoleRandomTalkContent = {};

-- 每次发言检查时间间隔
local TALK_CHECK_INTERVAL = 3;

-- 发言冷却时间
local TALK_INTERVAL = 6;

local GRID_TALK_CD_TIME = 12;

local alreadyTalkedList = {};

-- 最近一次触发时间
local lastTalkTime = 0;

-- 角色发言队列
local roleTalkQueue = {};

-- 当前夹层角色的位置关系
local unrealRolePos = {};

-- 每个格子发言
local gridsLastTalkTimeMap = {};

-- 函数
local generateRoleTalk;
-- 是否在冷却时间内
local isInTalkCD;
-- 触发发言
local triggerRoleTalk;
-- 抽取发言
local fetchTalkList;
-- 内部函数声明
local whenLeaveDungeon = nil;

-- 载入配置表
local _init = false;
local loadCsv = function()
    if _init then return end
    _init = true;

    CreationGateBonusTable = {};
    local creation_gate_bonus_CSV = get_creation_gate_bonus_CSV();
    for i = 1, #creation_gate_bonus_CSV do
        local id = creation_gate_bonus_CSV[i].id;
        CreationGateBonusTable[id] = parseRow(creation_gate_bonus_CSV[i]);
    end

    -- 创世之门夹层奖励
    CreationUnrealTable = {};
    RoleTypeInfo = {};
    -- 随机发言内容
    RoleRandomTalkContent = {};

    local creation_unreal_CSV = get_creation_unreal_CSV();
    for i = 1, #creation_unreal_CSV do
        local id = creation_unreal_CSV[i].id;
        CreationUnrealTable[id] = creation_unreal_CSV[i];

        -- 根据不同类型
        local roleType = creation_unreal_CSV[i].type;
        local times = creation_unreal_CSV[i].times;
        if RoleTypeInfo[roleType] == nil then
            RoleTypeInfo[roleType] = {};
        end

        RoleTypeInfo[roleType][times] = creation_unreal_CSV[i];

        -- 角色发言
        local buildingTalk = creation_unreal_CSV[i].building_talk;
        if type(buildingTalk) == "string" and buildingTalk ~= "" then
            if RoleRandomTalkContent[roleType] == nil then
                RoleRandomTalkContent[roleType] = {};
            end

            table.insert(RoleRandomTalkContent[roleType], id);
        end
    end

    CreationGateDialogTable = {};
    local creation_gate_dialog_CSV = get_creation_gate_dialog_CSV();
    for i = 1, #creation_gate_dialog_CSV do
        local id = creation_gate_dialog_CSV[i].id;
        CreationGateDialogTable[id] = creation_gate_dialog_CSV[i];
    end

    creation_gate_bonus_CSV = {};
    creation_unreal_CSV = {};
    creation_gate_dialog_CSV = {};
end

-- 初始化
function init()
    loadCsv();

    EventMgr.remove("CreationGateM", event.LEAVE_DUNGEON);

    EventMgr.register("CreationGateM", event.LEAVE_DUNGEON, whenLeaveDungeon);
end

-- 离开迷宫回调
whenLeaveDungeon = function()
    -- 创世之门物品奖励
    ME.user.dbase:delete("creation_gate_item_bonus");
end

-- 解析奖励信息
function parseBonus(bonus)
    local arr = string.explode(bonus, "+");
    local bonusList = {};
    local temp;
    for _, str in pairs(arr) do
        if str ~= "" then
            if string.startWith(str, "1(") and string.endWith(str, ")") then
                -- 物品奖励
                temp = string.explode(string.sub(str, 3, -2), ",");
                table.insert(bonusList, {1, tonumber(temp[1]), tonumber(temp[2]) });
            elseif string.startWith(str, "2(") and string.endWith(str, ")") then
                -- 属性奖励
                temp = string.explode(string.sub(str, 3, -2), ",");
                table.insert(bonusList, {2, temp[1], tonumber(temp[2]) });
            elseif string.startWith(str, "3(") and string.endWith(str, ")") then
                -- 冈布奥奖励
                temp = string.explode(string.sub(str, 3, -2), ",");
                table.insert(bonusList, {3, tonumber(temp[1]), tonumber(temp[2]) });
            else
                assert(false, "奖励类型配置错误");
            end
        end
    end
    return bonusList;
end

-- 解析行
function parseRow(row)
    row["bonus"] = parseBonus(row["bonus"]);
    return row;
end

-- 检索奖励信息
function query(id, path)
    local m = CreationGateBonusTable[id]

    if not m or path == "" or not path then
        return m
    end

    return m[path]
end

-- 检索创世之门夹层信息
function queryUnrealInfo(id, path)
    local m = CreationUnrealTable[id];

    if not m or path == "" or not path then
        return m;
    end

    return m[path];
end

-- 根据次数和角色获得当前当前信息
function queryRoleInfo(roleType, times, path)
    local m = RoleTypeInfo[roleType] or {};

    local info = m[times];

    if not info or path == "" or not path then
        return info;
    end

    return info[path];
end

-- 检索创世之门对话信息
function queryDialogInfo(roleId, path)
    local m = CreationGateDialogTable[roleId];

    if not m or not path or path == "" then
        return m;
    end

    return m[path];
end

-- 获取所有奖励
function getAllBonusConfig()
    return CreationGateBonusTable;
end

-- 判断是否可以提交
function canSubmit(classId)

    local keyIds = FormulaM.invoke("GET_CREATIONGATE_KEYS");
    local haveKey = false;

    for _, v in pairs(keyIds) do
        if(table.indexOf(v, classId) ~= -1) then
            haveKey = true;
        end
    end

    -- 非创世之门钥匙不提交
    if not haveKey then
        return false;
    end

    if(ItemM.getAmount(ME.user, classId) < 1) then
        return false;
    end

    return true;
end

-- 提交钥匙
function submitKey(classId)
    if not canSubmit(classId) then
        return false;
    end

    -- 扣除物品
    ItemM.costAmount(ME.user, classId, 1);

    -- 获得奖励
    local bonusList = getBonusList();

    -- 逐个执行奖励
    for _, bonus in pairs(bonusList) do
        BonusM.doBonus(bonus, "creation_gate_bonus");
    end

    return true;
end

-- 提交道具
function submitEquip(classId)
    if not canSubmit(classId) then
        return false;
    end

    -- 扣除物品
    ItemM.costAmount(ME.user, classId, 1);

    -- 获得奖励
    local bonusMap = {
        [7217] = {{2,"attack",10},{2,"magic",10},{2,"max_hp",200},{2,"max_mp",200},{2,"search_point",1000}},
        [7218] = {{2,"attack",10},{2,"magic",10},{2,"max_hp",200},{2,"max_mp",200},{2,"search_point",1000}},
        [8111] = {{1,7641,1}},
    }
    local bonusList = bonusMap[classId] or {};

    -- 逐个执行奖励
    for _, bonus in pairs(bonusList) do
        BonusM.doBonus(bonus, "creation_gate_bonus");
    end

    return true;
end

-- 进入夹层检查入场发言
function checkRoleTalk()
    if not isInCreationUnreal() then
        return;
    end

    -- 获得所有的GRID_TYPE_CG_UNREAL_OBJ位置
    local class = DungeonM.getClassByType(GRID_TYPE_CG_UNREAL_OBJ);
    local grids = CombatM.filterByClass(DungeonM.getCurrentDungeon(), class);

    for _, grid in pairs(grids) do
        local pos = grid.pos;
        local roleType = grid.role_type;

        -- 初始化角色位置信息
        unrealRolePos[roleType] = pos;

        local content = queryDialogInfo(roleType, "appear_dialog") or "";

        if roleType ~= 5 or not PetM.getMyPet(118) then

            -- 抛出发言事件
            EventMgr.fire(event.AUDIENCE_TALK, { ["pos"] = pos, ["content"] = content, ["delay"] = 0.5, ["talkType"] = "special_monster"});
        end
    end

    -- 定期触发角色发言
    ScheduleM.createScheme("CreationGateM", generateRoleTalk, TALK_CHECK_INTERVAL, true)
end

-- 是否在创世之门夹层
function isInCreationUnreal()
    if not UnrealDungeonM.isInUnreal() then
        return false;
    end

    local unrealId = UnrealDungeonM.getUnrealId();
    local dbase = UnrealDungeonM.query(unrealId, "dbase");
    if dbase["creation_gate"] ~= 1 then
        return false;
    end

    return true;
end

-- 响应发言队列中的请求
execTalkQueue = function()
    if #roleTalkQueue == 0 then
        return;
    end

    -- 如果队列中有发言请求，逐个触发
    for _, item in pairs(roleTalkQueue) do
        local pos   = item.pos;
        local delay = item.delay;
        local content = queryUnrealInfo(item.id, "building_talk");
        triggerRoleTalk(pos, content, delay);
    end

    roleTalkQueue = {};
end

prepareRoleTalk = function()
    local curTime = os.time();

    if (curTime - lastTalkTime) < TALK_INTERVAL then
        -- 发言冷却
        return;
    end

    -- 随机挑选几个发言位置
    local talkList = fetchTalkList();

    for id, pos in pairs(talkList) do
        -- 随机延时一下，错开发言时间
        local delay = math.random(1, 10)/10;

        local item = { ["pos"] = pos, ["id"] = id, ["delay"] = delay,};
        table.insert(roleTalkQueue, item);
    end

    -- 记录最近一次发言的时间
    lastTalkTime = curTime;
end

-- 定时生成角色发言内容
generateRoleTalk = function()
    if not isInCreationUnreal() then
        -- 不在创世之门夹层中
        -- 注销调度器
        ScheduleM.deleteScheme("CreationGateM");
        return;
    end

    -- 如果发言队列不为空，直接响应请求
    if #roleTalkQueue > 0 then
        execTalkQueue();
        return;
    end

     prepareRoleTalk();
end

-- 是否在发言冷却中
isInTalkCD = function(pos)
    local gridLastTalkTime = gridsLastTalkTimeMap[pos];
    if type(gridLastTalkTime) ~= "number" then
        return false;
    end

    if os.time() - gridLastTalkTime >= GRID_TALK_CD_TIME then
        return false;
    end

    return true;
end

-------------------------------
-- 触发角色发言
-- @param pos     格子位置
-- @param content 发言内容
-- @param delay   延时几秒后播放
triggerRoleTalk = function(pos, content, delay)
    delay = delay or 0;

    -- 记录该格子最近一次发言时间
    gridsLastTalkTimeMap[pos] = os.time() + delay;

    -- 抛出发言事件
    EventMgr.fire(event.AUDIENCE_TALK, { ["pos"] = pos, ["content"] = content, ["delay"] = delay, ["talkType"] = "special_monster"});
end

-- 抽取发言id和对应位置
fetchTalkList = function()
    local count = 0;
    local talkList = {};

    -- 找到可发言的列表
    local roleTypeList = {};

    -- 所有可以发言的角色
    local allTalkRoleList = {};
    for roleType, pos in pairs(unrealRolePos) do
        local talkIds = RoleRandomTalkContent[roleType] or {};
        -- peter不发言
        if #talkIds > 0 then

            table.insert(allTalkRoleList, roleType);

            if not isInTalkCD(pos) then
                table.insert(roleTypeList, roleType);
            end
        end
    end

    -- 随找一个角色发言
    local talkRole;
    local count = sizeof(roleTypeList);
    if  count > 0 then
        talkRole = roleTypeList[math.random(count)];
    else
        talkRole = allTalkRoleList[math.random(count)];
    end

    local contentIds = table.deepcopy(RoleRandomTalkContent[talkRole]) or {};

    local rolePos = unrealRolePos[talkRole]

    -- 去掉已经发言的
    local alreadyList = alreadyTalkedList[rolePos] or {};

    if #alreadyList == #contentIds then
        alreadyList = {};
    end

    for _, index in pairs(alreadyList) do
        table.remove(contentIds, index);
    end

    -- 抽取发言内容
    local index = math.random(sizeof(contentIds));
    local id = contentIds[index];

    -- 记录一下已经说过了的
    table.insert(alreadyList, index);

    talkList[id] = rolePos;

    alreadyTalkedList[rolePos] = alreadyList;

    return talkList;
end

-- 获得奖励列表
function getBonusList()
    local idsArr = {};

    local curDungeonTimes = ME.user.dbase:query("creation_gate_item_bonus") or {};
    local sumTimes = calcCurDungeonTimes(curDungeonTimes);

    for k, v in pairs(CreationGateBonusTable) do
        -- 等于0的次数不受限制
        if v.times_limit == 0 then
            table.insert(idsArr, k);
        elseif sumTimes < 2 then
            local curItemTimes = curDungeonTimes[k];
            if curItemTimes == nil then
                curItemTimes = 0;
            end

            local index = v.index;
            if index > 0 and v.times_limit > BuffDataM.query("creation_gate_limit", index) and curItemTimes < 1 then
                table.insert(idsArr, k);
            end
        end
    end

    -- 抽奖前先排序
    local function sortItem(id1, id2)
        return id1 < id2;
    end
    table.sort(idsArr, sortItem);
    printTable(idsArr, "idsArr");

    -- 获取随机数
    local rand = DungeonM.getRandSeed("creation_gate");

    local index = rand % #idsArr;
    local id = idsArr[index + 1];

    -- 计算次数加1
    local inf = query(id);
    if inf["index"] > 0 then
        local times = tonumber(BuffDataM.query("creation_gate_limit", 1));
        BuffDataM.set("creation_gate_limit", 1, times + 1);
        curDungeonTimes[id] = 1;
    end

    -- 本次迷宫奖励相关的
    ME.user.dbase:set("creation_gate_item_bonus", curDungeonTimes);

    return query(id, "bonus");
end

-- 计算当前迷宫次数
function calcCurDungeonTimes(para)
    local sum = 0;
    for k, v in pairs(para) do
        sum = sum + v;
    end
    return sum;
end

-- 获得每次打开的相关信息,
-- 返回值第一个是否显示对话，
-- 当前信息
function GetCurTimesDesc(grid)
    local roleType = grid.role_type;

    -- 上次的次数
    local curTimes = tonumber(grid.times) + 1;

    -- 如果次数限制如果当前次数限制的检查下对应的次数
    local curInfo = queryRoleInfo(roleType, curTimes);

    -- 检查奖励限制
    while type(curInfo) == "table" do

        local buffIndex = tonumber(curInfo.buff_index);
        if buffIndex > 0 and BuffDataM.query("creation_unreal_limit", buffIndex) > 0 then
            -- 检查是否领取过
            curTimes = curTimes + 1;
        else
            -- 如果奖励的是peter
            local btnText = getLocStr("leave");
            local bonus = curInfo.bonus or {};
            if type(bonus[1]) == "table" and bonus[1][1] == 3 then
                btnText = getLocStr("btn_text_what");
            end

            return true, {["title"] = queryDialogInfo(roleType, "name"),
                    ["btn_text"] = btnText,
                    ["desc"] = curInfo["building_desc"], ["content"] = curInfo["building_talk"]};
        end

        curInfo = queryRoleInfo(roleType, curTimes);
    end

    -- curInfo不存在的话,提示不再理会
    return false, {["desc"] = queryDialogInfo(roleType, "sys_tip"),};
end

-- 领取奖励
function takeCGUnrealBonus(pos)
    -- 根据当前对话次数来领取奖励
    local grid = DungeonM.getGridByPos(pos);

    if not grid then
        trace("CreationGateM", "位置(%d)的格子不存在。", pos);
        return false;
    end

    local gridType = grid.type;

    if gridType ~= GRID_TYPE_CG_UNREAL_OBJ then
        return false;
    end

    if grid.state == GRID_STATE_DIABLE then
        return false;
    end

    local curTimes = tonumber(grid.times) + 1;

    -- 如果次数限制如果当前次数限制的检查下对应的次数
    local roleType = grid.role_type or 1;
    local curInfo = queryRoleInfo(roleType, curTimes);

    local buffIndex = 0;

    -- 检查奖励限制
    while type(curInfo) == "table" do

        buffIndex = tonumber(curInfo.buff_index);
        if buffIndex > 0 and BuffDataM.query("creation_unreal_limit", buffIndex) > 0 then
            -- 检查是否领取过
            curTimes = curTimes + 1;
        else
            break;
        end

        curInfo = queryRoleInfo(roleType, curTimes);
    end

    grid.times = curTimes;

    if type(curInfo) ~= "table" then
        return false;
    end

    -- 当前没有奖励就要不奖
    if type(curInfo.bonus) ~= "table" then
        return true;
    end

    local classId;
    local seed;
    local temp;
    local realBonus = {};
    for k, v in pairs(curInfo.bonus) do
        -- 解析奖励
        if type(v[2]) == "table" then
            seed = DungeonM.getRandSeed("creation_unreal");
            temp = v[2];
            classId = temp[1 + seed % #temp];
        else
            classId = v[2];
        end

        BonusM.doBonus( {v[1], classId, v[3]}, "cg_unreal_bonus");

        -- 记录下奖励
        table.insert(realBonus, {v[1], classId, v[3]});
    end

    -- 标记特殊奖励已经领取
    if buffIndex > 0 then
        BuffDataM.set("creation_unreal_limit", buffIndex, 1)
    end

    EventMgr.fire(event.CG_UNREAL_BONUS, {["bonus"] = realBonus, ["pos"] = pos});

    return true;
end

--  领取商品奖励
function takeCreationDoorBonus(pos)
    -- 根据当前对话次数来领取奖励
    local grid = DungeonM.getGridByPos(pos);

    if not grid then
        trace("CreationGateM", "位置(%d)的格子不存在。", pos);
        return false;
    end

    local gridType = grid.type;

    if gridType ~= GRID_TYPE_CREATION_DOOR then
        return false;
    end

    if grid.state == GRID_STATE_DIABLE then
        return false;
    end

    local bonus = {};

    -- 检查是否已经领取过了
    if BuildingBonusM.getFieldStat("world_source_bonus") == 0 then
        bonus = {1, 7643, 1};
    else
        bonus = {1, 7644, 1};
    end

    BonusM.doBonus(bonus, "creation_door");

    EventMgr.fire(event.CREATION_DOOR_BONUS, {["bonus"] = bonus, ["pos"] = pos});

    return true;
end